#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

#define BUFLEN          65507
#define MAXADDRLEN      256

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX   256
#endif

void serve(int sockfd)
{
    int         n;
    socklen_t   alen;
    FILE        *fp;
    char        buf[BUFLEN];
    char        abuf[MAXADDRLEN];

    for (;;) {
        alen = MAXADDRLEN;
        if ((n = recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr *)abuf, 
                    &alen)) < 0) {
            perror("recvfrom error");
            exit(0);
        }

        printf("recvfrom success\n");

        if ((fp = popen("/usr/bin/uptime", "r")) == NULL) {
            sprintf(buf, "error: %s\n", strerror(errno));
            sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)abuf, alen);
        }
        else {
            if (fgets(buf, BUFLEN, fp) != NULL) 
                sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)abuf,
                    alen);
            pclose(fp);
        }
    }
}

int main(int argc, char *argv[])
{
    struct addrinfo *ailist, *aip;
    struct addrinfo hint;
    int             sockfd, err, n, reuse;
    char            *host;

#ifdef _SC_HOST_NAME_MAX
    n = sysconf(_SC_HOST_NAME_MAX); /* 64 */
    if  (n < 0)
#endif
    n = HOST_NAME_MAX;

    host = malloc(n);
    if (host == NULL) {
        perror("malloc error");
        exit(0);
    }

    if (gethostname(host, n) < 0) {
        perror("gethostname error");
        exit(0);
    }

    hint.ai_flags = AI_CANONNAME;
    hint.ai_family = 0;
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_protocol = 0;
    hint.ai_addrlen = 0;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;
    if ((err = getaddrinfo(host, "8320", &hint, &ailist)) != 0) {
        printf("getaddrinfo error: %s\n", gai_strerror(err));
        exit(0);
    }

    for (aip = ailist; aip !=  NULL; aip = aip->ai_next) {
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd < 0) {
            perror("sock error");
            exit(0);
        }
        
        reuse = 1;
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse,
                sizeof(int)) < 0) {
            perror("setsockopt error");
            exit(0);
        }

        if (bind(sockfd, aip->ai_addr, aip->ai_addrlen) < 0) {
            perror("bind error");
            exit(0);
        }

        printf("bind at %s:%d\n", inet_ntoa(((struct sockaddr_in *)aip->ai_addr)->sin_addr), 
            ntohs(((struct sockaddr_in *)aip->ai_addr)->sin_port));

        serve(sockfd);
        exit(0);
    }

    return 0;
}
